package com.lagou.edu.config;


import com.lagou.edu.anno.Autowired;
import com.lagou.edu.anno.Service;
import com.lagou.edu.anno.Transactional;
import com.lagou.edu.factory.ProxyFactory;

import java.io.IOException;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;

import static com.lagou.edu.utils.Help.*;

public class BeanFactory  {
    // 存储对象
    private static ConcurrentHashMap<String, Object> beansMap = new ConcurrentHashMap<>();

    //扫描路径
    private String basePackage="com.lagou.edu";

    private ClassLoader cl=getClass().getClassLoader();;





    /**
     * 获取指定包下的所有字节码文件的全类名
     */

    public List<String> initBeans() throws Exception {
        return doScan(basePackage, new ArrayList<>());
    }

    /**
     * 读取class
     *
     * @param basePackage
     * @param nameList
     * @return
     * @throws IOException
     */
    private List<String> doScan(String basePackage, List<String> nameList) throws IOException, ClassNotFoundException, IllegalAccessException, InstantiationException {
        String splashPath = StringUtil.dotToSplash(basePackage);
        URL url = cl.getResource(splashPath);
        String filePath = StringUtil.getRootPath(url);
        List<String> names = null;
        if (isJarFile(filePath)) {
            names = readFromJarFile(filePath, splashPath);
        } else {
            names = readFromDirectory(filePath);
        }
        for (String name : names) {
            if (isClassFile(name)) {
                nameList.add(toFullyQualifiedName(name, basePackage));
            } else {
                doScan(basePackage + "." + name, nameList);
            }
        }
        for (String n : nameList) {
            Class<?> aClass = Class.forName(n);
            try {
                if (!aClass.isAnnotation()) {
                    Service annotationField = aClass.getAnnotation(Service.class);
                    if (annotationField != null) {
                        Object o = aClass.newInstance();
                        // 实例化之后的对象
                        // 存储到map中待用
                        Class<?>[] interfaces = aClass.getInterfaces();
                        if (interfaces.length > 0) {
                            beansMap.put(interfaces[0].getName(), o);
                        } else {
                            beansMap.put(n, o);
                        }

                    }
                }
            } catch (Exception e) {
                System.out.println(n);
            }
        }
        return nameList;
    }




    public static void creatBeanFactory() throws Exception {
         new BeanFactory().initBeans();
        beansMap.forEach((beanId, beanObject) ->{
            Class<?> beanClass = beanObject.getClass();
            //autowire注入对象
            try {
                autowire(beanObject, beanClass);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
            //Transactional进行代理增强
            transactional( beanClass);
        });


    }

    private static void transactional( Class<?> aClass) {
        Transactional transactional = aClass.getAnnotation(Transactional.class);
        if(transactional!=null){
            //获取当前对象接口
            Class<?>[] beanClassInterfaces = aClass.getInterfaces();
            ProxyFactory proxyFactory= (ProxyFactory) getBean("com.lagou.edu.factory.ProxyFactory");
            if(beanClassInterfaces.length>0){
                proxyFactory.getJdkProxy(aClass);
            }else {
                  proxyFactory.getCglibProxy(aClass);
            }

        }
    }

    private static void autowire(Object parentObject, Class<?> aClass) throws IllegalAccessException {

        //取成员对象
        Field[] fields = aClass.getDeclaredFields();
        for (Field f : fields) {
            //判断是否有注解
            Autowired annotationField = f.getAnnotation(Autowired.class);
            if (annotationField != null) {
                //去容器找类对象
                Object o;
                o = beansMap.get(f.getType().getName());
                if (o != null) {
                    //找到了就给改变量赋值
                    f.setAccessible(true);
                    f.set(parentObject, o);
                }
            }
        }
    }
//获取bean
    public static Object getBean(String str) {
        return beansMap.get(str);
    }
}